/******************************************************************************************************
Copyright (C) 2017 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/*globals date2ISOString, mainWindow, qsTr, settings, Application, Dir, ImportMnovaConfiguration_Engine, File, FileDialog, IniFile, MessageBox, MnUi, ProgressDialog, Settings, TextStream*/

/*jslint plusplus: true, continue:true, indent: 4*/

function ImportMnovaConfiguration() {
	"use strict";

	var file, fileObject, directory, engine, engineResult, lastWorkingDirectory, lastWorkingDirectoryKey;

	lastWorkingDirectoryKey = "Import Mnova Configuration/Last Directory";

	//We wet the last working directory from settings
	lastWorkingDirectory = settings.value(lastWorkingDirectoryKey, Dir.home());
	directory = new Dir(lastWorkingDirectory);
	if (!(directory.exists)) {
		lastWorkingDirectory = Dir.home();
	}

	//Get the INI file path
	file = FileDialog.getOpenFileName("*.ini", "Select a INI to be imported", lastWorkingDirectory);
	if (file !== undefined && file !== "") {

		fileObject = new File(file);
		if (fileObject.exists) {
			lastWorkingDirectory = fileObject.absDirPath;

			//Instance the ini in order to import the data
			engine = new ImportMnovaConfiguration_Engine(file);
			engineResult = engine.process();

			//Save values to the registry
			settings.setValue(lastWorkingDirectoryKey, lastWorkingDirectory);

			//Shows an ending message to the user
			if (typeof (engineResult) === "boolean" && engineResult) {
				mainWindow.writeSettingsOnClose = false;
				MessageBox.information(qsTr("The importation process has been performed successfully\nIt is necessary to restart the application for the changes to take effect"));
			} else if (typeof (engineResult) === "boolean" && !engineResult) {
				MessageBox.critical(qsTr("The importation process has not been performed"));
			} else if (!isNaN(engineResult)) {
				mainWindow.writeSettingsOnClose = false;
				MessageBox.warning(qsTr("The importation process did not imported {0} keys\nIt is necessary to restart the application for the changes to take effect").format(engineResult));
			}
		}
	}
}

//----------------------------STATIC CLASS METHODS----------------------------
function ImportMnovaConfiguration_Engine(aIniFilePath) {
	"use strict";

	//Set instance attributes from parameters
	this.file = aIniFilePath;
	this.rootFolderOfMnova = "/";

	ImportMnovaConfiguration_Engine.prototype.deleteAllChildKeys = function (aSettingsFolderPath) {

		var i, settingsObject, keysToBeDeleted, key;

		settingsObject = new Settings(aSettingsFolderPath);
		keysToBeDeleted = settingsObject.childKeys();
		for (i = 0; i < keysToBeDeleted.length; i++) {
			key = keysToBeDeleted[i];
			settingsObject.remove(key);
		}
		settingsObject = new Settings("/");
		settingsObject.remove(aSettingsFolderPath);
	};

	ImportMnovaConfiguration_Engine.prototype.eleMentDoesNotExistInArray = function (aValue, aArray) {

		var i, result;

		result = false;
		for (i = 0; i < aArray.length; i++) {
			if (aValue === aArray[i]) {
				result = true;
				break;
			}
		}

		return result;
	};

	ImportMnovaConfiguration_Engine.prototype.getFolderKeys = function (aIniSettingsContainer) {

		var i, j, setts, childKeys, key, keyArray, folders, currentFolder;

		//Get all items folders
		folders = [];
		setts = new IniFile(aIniSettingsContainer);
		childKeys = setts.allKeys();
		for (i = 0; i < childKeys.length; i++) {
			key = "/" + childKeys[i];
			keyArray = key.split("/");

			//Mnova root keys
			if (keyArray.length === 2) {
				currentFolder = "/";
				if (!this.eleMentDoesNotExistInArray(currentFolder, folders)) {
					folders.push(currentFolder);
				}

			//Folders below mnova root level
			} else if (keyArray.length > 2) {
				currentFolder = "";
				for (j = 0; j < keyArray.length - 1; j++) {
					currentFolder += keyArray[j];
					if (j < keyArray.length - 2) {
						currentFolder += "/";
					}
				}
				if (!this.eleMentDoesNotExistInArray(currentFolder, folders)) {
					folders.push(currentFolder);
				}
			}
		}

		return folders;
	};

	ImportMnovaConfiguration_Engine.prototype.process = function () {

		var i, result, iniFilePath, foldersToBeDeletedAndImported, currentFolder, iniSetts,	auxResult, auxResult2,
			newChildKeys, currentNewKeyName, currentNewValue, settings, restoredValue, counterSuccesfullyRestoredKeys;

		result = false;
		iniFilePath = this.file;
		if (File.exists(iniFilePath)) {

			//Delete all keys in the selected folders which will be imported
			foldersToBeDeletedAndImported = this.getFolderKeys(iniFilePath);
			for (i = 0; i < foldersToBeDeletedAndImported.length; i++) {
				currentFolder = foldersToBeDeletedAndImported[i];
				this.deleteAllChildKeys(currentFolder);
			}

			//Create source and destination containers and it also get all keys to be imported
			iniSetts = new IniFile(iniFilePath);
			settings = new Settings("/");
			newChildKeys = iniSetts.allKeys();

			//Import the new data to the destination settings
			counterSuccesfullyRestoredKeys = 0;
			for (i = 0; i < newChildKeys.length; i++) {
				currentNewKeyName = "/" + newChildKeys[i];
				currentNewValue = iniSetts.value(currentNewKeyName);
				settings.setValue(currentNewKeyName, currentNewValue);
				restoredValue = settings.value(currentNewKeyName);

				//Get data for comparing. We assume objects will be always QByteArray
				try {
					if (typeof (currentNewValue) === "object") {
						auxResult = currentNewValue.toBase64().toString();
					} else {
						auxResult = currentNewValue.toString();
					}
				//If is a variant type we can't compare through scrpting engine. So we assume they are equals
				} catch (e) {
					counterSuccesfullyRestoredKeys++;
					continue;
				}

				//Get new data for comparing
				try {
					if (typeof (restoredValue) === "object") {
						auxResult2 = restoredValue.toBase64().toString();
					} else {
						auxResult2 = restoredValue.toString();
					}
				//If is a variant type we can't compare through scrpting engine. So we assume they are equals
				} catch (err) {
					counterSuccesfullyRestoredKeys++;
					continue;
				}

				//Compare backup and restore values
				if (auxResult.trim() === auxResult2.trim()) {
					counterSuccesfullyRestoredKeys++;
				}
			}

			//Check if the keys imported matches with the number of keys into the ini file
			if (counterSuccesfullyRestoredKeys === newChildKeys.length) {
				result = true;
			} else if (counterSuccesfullyRestoredKeys === 0) {
				result = false;
			} else {
				result = Math.abs(newChildKeys.length - counterSuccesfullyRestoredKeys);
			}
		}

		return result;
	};
}

function ImportMnova() {
	'use strict';

	var viewer;

	//Instance the script by using the Application global variable
	try {
		viewer = new ImportMnovaConfiguration();
	} catch (Err) {
		MessageBox.critical(Err);
	}

	return viewer;
}

if (this.MnUi && this.MnUi.scripts_common) {
	MnUi.scripts_common.scripts_common_ImportMnovaConfiguration = ImportMnova;
}
